#include "Docxconv.h"
#include <iterator>
#include <fstream>
#include <Tools.h>
#include <boost/filesystem.hpp>
#include <boost/process.hpp>
#include <iostream>

//utf8
#include "utf8.h"

//xmlwrapp headers
#include <xsltwrapp/xsltwrapp.h>
#include <xmlwrapp/xmlwrapp.h>

//! EventParser 
/*!
	Trieda sluziaca ako receptor udalosti ktore vznikaju pri
	parsovani xml dokumentu.
*/
class EventParser : public xml::event_parser
{
	public:
		
		std::wstring GetText()
		{
			return myParsedText;
		}

	private:
		bool addText;

		std::wstring myParsedText;
		//! text (private )
		/*!
			Metoda sa zavola ak sa nacita text z xml dokumentu
			\param const std::string & theInput nacitany text
			\return bool true
		*/
		bool text (const std::string &theInput)
		{
			if(addText)
			{
				utf8::utf8to16(theInput.begin(),theInput.end(),back_inserter(myParsedText));
			}
			
			return true;
		}

		bool start_element (const std::string &name, const attrs_type&)
		{
			if(name == "w:t")
			{
				addText = true;
			}
			return true;
		}

		
		bool end_element (const std::string &name)
		{ 
			if(name == "w:p")	//ked 
			{
				myParsedText.append(L"\n");
			}
			else if(name == "w:t")
			{
				addText = false;
			}
			return true;   
		}
};




Docxconv::Docxconv(void)
{
	myZipfile = NULL;
	std::string aXSLFileName = "DocX2Html.xslt";
	std::string aPluginPath;

	boost::process::self &mySelf = boost::process::self::get_instance();
	boost::process::environment env = mySelf.get_environment();
	for(boost::process::environment::iterator it = env.begin(); it != env.end(); ++it)
	{
		if (it->first == "plag_plugin_path")
		{
			aPluginPath = it->second;
		}
	}

	if(aPluginPath.empty())
	{
		std::cerr << "Cant find the enviroment variable plag_plugin_path, please set it first.." << std::endl;
		throw std::runtime_error("no enviroment variable");
	}

    myXSLFile = aPluginPath + aXSLFileName;

	if(!boost::filesystem::exists(myXSLFile))
	{
		std::cerr << "Cant find the file: DocX2Html.xslt" << std::endl;
		throw std::runtime_error("Cant find :" +myXSLFile);
	}
}

Docxconv::~Docxconv(void)
{
	delete myZipfile;
}


bool Docxconv::Open(PComunicator::PFileInfo &theFile)
{
	if(!theFile.GetFileType().empty() && theFile.GetFileType() != "docx")
		return false;

	delete myZipfile;
	myDocName = theFile.GetFullName();

	try
	{
		myZipfile = new zipios::ZipFile(theFile.GetFile());
		zipios::ConstEntries entries = myZipfile->entries();
		zipios::ConstEntries::iterator iter;

		for(iter = entries.begin(); iter != entries.end(); iter++)
		{
			if( (*iter)->isDirectory())
				continue;		
			else
			{
				if( (*iter)->getFileName() == "document.xml" )
				{
					std::string fullFileName = (*iter)->getName();
					zipios::ConstEntryPointer entri = myZipfile->getEntry(fullFileName,zipios::FileCollection::ZIP_MATCH);
					std::istream *pIstream = myZipfile->getInputStream(entri);
					myDocFile.assign(std::istreambuf_iterator<char>((*pIstream)), std::istreambuf_iterator<char>());
					delete pIstream;
					return true;
				}
			}
		}

		return true;
	}
	catch(std::exception)
	{
		return false;
	}

	return false;
}

std::wstring Docxconv::Read()
{
	EventParser _parser;
	_parser.parse_chunk(myDocFile.c_str(),myDocFile.size());

	return _parser.GetText();
}



std::string Docxconv::CreateHtml(std::string thePath)
{
	if(!boost::filesystem::exists(thePath))
	{
		boost::filesystem::create_directories(thePath);
	}

	//parsujeme hlavny document z docx suboru(document.xml)
	xml::tree_parser parser(myDocFile.c_str(),myDocFile.size());
	xml::document &doc = parser.get_document();

	//treba rozparsovat XSL dokument pouzity na transformaciu
	xslt::stylesheet style(myXSLFile.c_str());

	//pouzijeme xsl transformaciu
	xml::document &result = style.apply(doc);

	std::string _newName = myDocName;
	Tools::Replace<std::string>(_newName,".docx",".html");
	
	std::string _newFullPath = thePath+_newName; 

	std::ofstream writer(_newFullPath.c_str());
	
	//vysledok transformacie zapiseme do suboru
	writer << result;
	writer.close();

	return _newFullPath;
}



std::string Docxconv::Format()
{
	return "docx";
}

char* Docxconv::Autor()
{
	return "Marek Szanyi";
}

char* Docxconv::Version()
{
	return "1.0";
}